#ifndef MULTIGRID_CLASSICALRAP_PMISAGGREGATION_HPP
#define MULTIGRID_CLASSICALRAP_PMISAGGREGATION_HPP

/*! \file pmisAggregation.hpp
 *  \author Zhao Chengpeng (chengpeng_zhao@foxmail.com)
 *  \date 2023-03-02
 *  \brief PMIS aggregation
 */

#include "csrMatrix.hpp"

namespace UNAP {

template <typename Cmpt>
class PMISAggregation {
 private:
  scalar eps_;                 /*!< parameter */
  label nAggr_;                /*!< aggregation num */
  const CSRMatrix<Cmpt>& A_;   /*!< input matrix */
  CSRMatrix<char> connection_; /*!< connection matrix */
  CSRMatrix<Cmpt> Ptent_;      /*!< prolongation operator */
  CSRMatrix<char>* matSquare(const CSRMatrix<char>& A);

  struct RugeStuben { /*!< only used when seq(np=1) */
    scalar epsStrong_;
    bool ifTrunc_;
    scalar epsTrunc_;
    RugeStuben() : epsStrong_(0.25), ifTrunc_(true), epsTrunc_(0.2) {}
    void build(const CSRMatrix<Cmpt>& A, CSRMatrix<Cmpt>& P);
    void connect(const CSRMatrix<Cmpt>& A, CSRMatrix<char>& S, Array<char>& cf);
    void splitcf(const CSRMatrix<Cmpt>& A, const CSRMatrix<char>& S,
                 Array<char>& cf);
  } RS_;

 public:
  PMISAggregation(const CSRMatrix<Cmpt>& A);
  virtual ~PMISAggregation() {}  // POUT << "deconstruct PMIS" << ENDL; }

  /*! build connection_ */
  void buildConnStrength();

  /*! coarsen */
  label aggregate(Array<label>& state, Array<label>& owner);

  /*! build Ptent_ */
  void buildTentativeProlongation(label naggr, Array<label>& state,
                                  Array<label>& owner);

  label size() const { return nAggr_; }
  virtual const CSRMatrix<Cmpt>& P() const { return Ptent_; }
  const CSRMatrix<char>& S() const { return connection_; }
};

} /* End namespace UNAP */
#endif /* end of include guard: MULTIGRID_CLASSICALRAP_PMISAGGREGATION_HPP */
